/*
 * include/linux/serial.h
 *
 * Copyright (C) 1992 by Theodore Ts'o.
 *
 * Redistribution of this file is permitted under the terms of the GNU
 * Public License (GPL)
 */
#ifndef SEMINIX_SERIAL_H
#define SEMINIX_SERIAL_H

#include <seminix/types.h>
#include <seminix/spinlock.h>

/*
 * These are the supported serial types.
 */
#define PORT_UNKNOWN	0
#define PORT_8250	1
#define PORT_16450	2
#define PORT_16550	3
#define PORT_16550A	4
#define PORT_CIRRUS     5	/* usurped by cyclades.c */
#define PORT_16650	6
#define PORT_16650V2	7
#define PORT_16750	8
#define PORT_STARTECH	9	/* usurped by cyclades.c */
#define PORT_16C950	10	/* Oxford Semiconductor */
#define PORT_16654	11
#define PORT_16850	12
#define PORT_RSA	13	/* RSA-DV II/S card */
#define PORT_MAX	13

#define SERIAL_IO_PORT	0
#define SERIAL_IO_HUB6	1
#define SERIAL_IO_MEM	2
#define SERIAL_IO_MEM32	  3
#define SERIAL_IO_AU	  4
#define SERIAL_IO_TSI	  5
#define SERIAL_IO_MEM32BE 6
#define SERIAL_IO_MEM16	7

#define UART_CLEAR_FIFO		0x01
#define UART_USE_FIFO		0x02
#define UART_STARTECH		0x04
#define UART_NATSEMI		0x08

/*
 * Console helpers.
 */
struct console_device {
    char	name[15];
    char	compatible[128];

    void	(*write)(struct console_device *, const char *, unsigned int);

    unsigned char		regshift;		/* reg offset shift */
    unsigned char		iotype;			/* io access style */

    resource_size_t		mapbase;
    unsigned long		iobase;			/* in/out[bwl] */
    unsigned char 	*membase;		/* read/write[bwl] */

    char options[16];		/* e.g., 115200n8 */
    unsigned int baud;
    unsigned int clk;

    char	available;

    spinlock_t		lock;			/* port lock */

    void	*private_data;
};

struct console_id {
    char	name[15];
    char	name_term;	/* In case compiler didn't '\0' term name */
    char	compatible[128];
    int	(*setup)(struct console_device *, const char *options);
};

extern const struct console_id *__console_table[];
extern const struct console_id *__console_table_end[];

#define CONSOLE_USED_OR_UNUSED	__used

#define _OF_CONSOLE_DECLARE(_name, compat, fn, unique_id)		\
    static const struct console_id unique_id			\
         CONSOLE_USED_OR_UNUSED __initconst			\
        = { .name = __stringify(_name),				\
            .compatible = compat,				\
            .setup = fn  };					\
    static const struct console_id CONSOLE_USED_OR_UNUSED		\
        __section(__console_table)				\
        * const __PASTE(__p, unique_id) = &unique_id

#define OF_CONSOLE_DECLARE(_name, compat, fn)				\
    _OF_CONSOLE_DECLARE(_name, compat, fn,				\
                 __UNIQUE_ID(__console_##_name))

extern int of_setup_console(const struct console_id *match,
                 unsigned long node,
                 const char *options);

extern bool console_device_available(void);

extern void console_write(const char *s, unsigned int count);

extern struct console_device console_dev;

static inline void console_device_lock(unsigned long *flags)
{
    spin_lock_irqsave(&console_dev.lock, *flags);
}

static inline void console_device_unlock(unsigned long *flags)
{
    spin_unlock_irqrestore(&console_dev.lock, *flags);
}

static inline void console_write_locked(const char *s, unsigned int count)
{
    if (likely(console_dev.available))
        console_dev.write(&console_dev, s, count);
}

#endif /* !SEMINIX_SERIAL_H */
